package quorum;
import common.Entity;
import utils.Hashes;
import common.Lists;
import java.util.Map;
import java.util.HashMap;

public class checkLive{
	Quorum quorum;
	Map<Entity,aliveTimer> listenPool;
	private static checkLive instance;
	private checkLive(Quorum q){
		quorum=q;
		listenPool=new HashMap<Entity,aliveTimer>();
	}
	public static boolean create(Quorum q){
		if(instance==null){
			instance=new checkLive(q);
			return true;
		}else{
			return false;
		}		
	}
	public synchronized static checkLive getInstance(){
		return instance;
	}
	
	public synchronized void addListenEntity(Entity e){
		aliveTimer toAdd=new aliveTimer(quorum,e);
		if(!listenPool.containsKey(e)){
			listenPool.put(e,toAdd);
			toAdd.start();
		}
	}
	
	public synchronized void removeListenEntity(Entity e){
		listenPool.get(e).kill();
		interrupt(e);
		listenPool.remove(e);
	}
	
	public synchronized void interrupt(Entity e){
		listenPool.get(e).interrupt();
	}
	
	public synchronized boolean isListening(Entity e){
		return listenPool.containsKey(e);
	}
	public synchronized boolean isListeningLeader(int group){
		if(group==Hashes.getGroupIdFromServerId(quorum.getId())){
			return true;
		}
		Entity[] set=(listenPool.keySet()).toArray(new Entity[0]);
		for(Entity entity:set){
			if(group==Hashes.getGroupIdFromServerId(entity.getId())){
				return true;
			}
		}
		return false;	
	}
	
	public synchronized boolean removeListenLeader(int group){
		if(group==Hashes.getGroupIdFromServerId(quorum.getId())){
			return true;
		}
		Entity[] set=(listenPool.keySet()).toArray(new Entity[0]);
		for(Entity entity:set){
			if(group==Hashes.getGroupIdFromServerId(entity.getId())){
				removeListenEntity(entity);
				return true;
			}
		}
		return false;	
	}
}
//------------------------------------------//
class aliveTimer extends Thread{
	private static boolean DEBUG=false;
	public static final int SLEEP_TIME = timer.aliveTime+30000;
	Quorum quorum;
	Entity listen;
	int reason; //0:reset timeout, 1:kill
	public aliveTimer(Quorum q, Entity e){
		reason=0;
		quorum=q;
		listen=e;
	}
	
	public void run(){
		while(true){
			try {
				waitSomeTime();
			} catch (InterruptedException e) {
				if(reason==1){
					if(DEBUG){
					System.out.print("thread killed\n");
					}
					return;//actively stop listening
				}
				if(DEBUG){
				System.out.print("thread interrupted\n");
				}
				continue;
			}
			if(DEBUG){
			System.out.print("someones dead\n");
			}
			int id=quorum.getId();
			int group=Hashes.getGroupIdFromServerId(id);
			int groupLeader=Lists.getInstance().getLiveServerGroup(group).peek().getId();
			int listengroup=Hashes.getGroupIdFromServerId(listen.getId());
			//this is group leader
			if(id==groupLeader){
				if(group==listengroup){
					quorum.detectDead(listen);
				}else{
					quorum.detectSiblingDead(listen);
				}
			}
			//this is not group leader, and group leader dies
			if(groupLeader==listen.getId()){
				quorum.detectLeaderDead(listen);
			}
			return;
		}
	}
	public synchronized void kill(){
		reason=1;
	}
	private void waitSomeTime() throws InterruptedException{
		if(DEBUG){System.out.print("thread wait 10000\n");}
		Thread.sleep(SLEEP_TIME);
	}
}